import sys
import os
import io
import re
import time
import ctypes
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTabWidget, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QLineEdit, QTextEdit, QPushButton,
                             QFileDialog, QGridLayout, QScrollArea, QFrame, QMessageBox)
from PyQt5.QtGui import QPixmap, QFont, QTextCursor, QIcon
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from txt_process import process_and_create_epub
import logging
from logging.handlers import RotatingFileHandler
import traceback


class LogRedirector(io.StringIO):
    def __init__(self, text_widget):
        super().__init__()
        self.text_widget = text_widget
        self.old_stdout = sys.stdout
        self.old_stderr = sys.stderr
        self.buffer = []
        self.buffer_size = 10  # 缓存大小
        self.last_flush_time = time.time()
        self.flush_interval = 0.1  # 刷新间隔（秒）

    def write(self, text):
        # 过滤空字符串和None
        if not text or text.isspace():
            return

        # 确保文本以换行符结尾
        if not text.endswith('\n'):
            text += '\n'

        try:
            # 添加到缓存
            self.buffer.append(text)

            # 当缓存达到指定大小或距离上次刷新超过指定时间时，执行刷新
            current_time = time.time()
            if len(self.buffer) >= self.buffer_size or \
               (current_time - self.last_flush_time) >= self.flush_interval:
                self._flush_buffer()

            # 安全地写入原始stdout
            if self.old_stdout and hasattr(self.old_stdout, 'write'):
                try:
                    self.old_stdout.write(text)
                except:
                    pass  # 忽略写入原始stdout的错误
        except Exception as e:
            print(f"日志重定向错误: {str(e)}")

    def _flush_buffer(self):
        if not self.buffer:
            return

        try:
            # 合并缓存中的所有文本
            text = ''.join(self.buffer)
            
            # 更新文本框
            self.text_widget.moveCursor(QTextCursor.End)
            self.text_widget.insertPlainText(text)
            self.text_widget.moveCursor(QTextCursor.End)
            QApplication.processEvents()

            # 清空缓存并更新最后刷新时间
            self.buffer.clear()
            self.last_flush_time = time.time()
        except Exception as e:
            print(f"刷新缓存错误: {str(e)}")

    def flush(self):
        self._flush_buffer()


class ConversionThread(QThread):
    finished = pyqtSignal(bool, str)

    def __init__(self, txt_path, book_name, author_name, desc, cover_image_path, back_image_path):
        super().__init__()
        self.txt_path = txt_path
        self.book_name = book_name
        self.author_name = author_name
        self.desc = desc
        self.cover_image_path = cover_image_path
        self.back_image_path = back_image_path
        # 获取日志记录器
        self.logger = logging.getLogger('txt2epub')

    def run(self):
        try:
            result = process_and_create_epub(
                self.txt_path,
                self.book_name,
                self.author_name,
                self.desc,
                self.cover_image_path,
                self.back_image_path
            )
            self.finished.emit(result, "")
        except Exception as e:
            # 记录完整的异常堆栈信息
            error_msg = traceback.format_exc()
            self.logger.error(f"转换失败: {error_msg}")
            self.finished.emit(False, str(e))


class ImageSelector(QFrame):
    def __init__(self, title, default_image, parent=None):
        super().__init__(parent)
        self.parent = parent
        self.selected_image_path = None

        self.setFrameShape(QFrame.Box)
        self.setFrameShadow(QFrame.Raised)
        self.setLineWidth(1)
        self.setMinimumSize(150, 200)
        self.setMaximumSize(200, 300)

        layout = QVBoxLayout(self)

        # 标题标签
        title_label = QLabel(title)
        title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        layout.addWidget(title_label)

        # 图片标签
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setMinimumSize(140, 180)
        self.image_label.setScaledContents(True)
        layout.addWidget(self.image_label)

        # 设置默认图片
        self.set_image(default_image)

        # 点击事件
        self.image_label.mousePressEvent = self.select_image

    def set_image(self, image_path):
        if image_path and os.path.exists(image_path):
            pixmap = QPixmap(image_path)
            self.image_label.setPixmap(pixmap)
            self.selected_image_path = image_path
        else:
            self.image_label.setText("点击选择图片")
            self.selected_image_path = None

    def select_image(self, event):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择图片", "", "图片文件 (*.jpg *.jpeg *.png)"
        )
        if file_path:
            self.set_image(file_path)

# 在MainWindow类的__init__方法中添加日志初始化


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        # 初始化日志系统
        self.init_logging()
        self.setWindowTitle("TXT转EPUB工具")
        # 设置程序图标
        icon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'favicon.ico')
        if os.path.exists(icon_path):
            self.setWindowIcon(QIcon(icon_path))
        self.resize(800, 600)

        # 创建标签页
        self.tabs = QTabWidget()
        self.setCentralWidget(self.tabs)

        # 创建书籍标签页
        self.book_tab = QWidget()
        self.tabs.addTab(self.book_tab, "书籍")

        # 创建日志标签页
        self.log_tab = QWidget()
        self.tabs.addTab(self.log_tab, "日志")

        # 设置书籍标签页布局
        self.setup_book_tab()

        # 设置日志标签页布局
        self.setup_log_tab()

        # 重定向标准输出到日志文本框
        self.log_redirector = LogRedirector(self.log_text)
        sys.stdout = self.log_redirector
        sys.stderr = self.log_redirector

    def init_logging(self):
        # 获取用户目录
        user_dir = os.path.expanduser('~')
        log_dir = os.path.join(user_dir, 'AppData', 'Roaming', 'txt2epub')
        log_file = os.path.join(log_dir, 'txt2epub.log')

        # 创建日志目录（如果不存在）
        os.makedirs(log_dir, exist_ok=True)

        # 创建日志记录器
        self.logger = logging.getLogger('txt2epub')
        self.logger.setLevel(logging.DEBUG)

        # 创建文件处理器，最大10MB，保留3个备份
        file_handler = RotatingFileHandler(
            log_file, maxBytes=10*1024*1024, backupCount=3, encoding='utf-8'
        )
        file_handler.setLevel(logging.DEBUG)

        # 创建日志格式
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(message)s'
        )
        file_handler.setFormatter(formatter)

        # 添加处理器
        self.logger.addHandler(file_handler)

    def setup_book_tab(self):
        layout = QVBoxLayout(self.book_tab)

        # 创建表单布局
        form_layout = QGridLayout()

        # 设置列拉伸因子，使第1列（索引为1）可以自动扩展
        form_layout.setColumnStretch(1, 1)

        # 小说文件选择
        form_layout.addWidget(QLabel("小说文件:"), 0, 0)
        self.txt_path_edit = QLineEdit()
        self.txt_path_edit.setReadOnly(True)
        form_layout.addWidget(self.txt_path_edit, 0, 1)
        self.browse_button = QPushButton("浏览...")
        self.browse_button.clicked.connect(self.browse_txt_file)
        form_layout.addWidget(self.browse_button, 0, 2)

        # 书名和作者名（放在同一行）
        form_layout.addWidget(QLabel("书名:"), 1, 0)
        self.book_name_edit = QLineEdit()
        form_layout.addWidget(self.book_name_edit, 1, 1)

        form_layout.addWidget(QLabel("作者:"), 2, 0)
        self.author_edit = QLineEdit()
        form_layout.addWidget(self.author_edit, 2, 1)

        # 小说简介
        form_layout.addWidget(QLabel("小说简介:"), 3, 0, Qt.AlignmentFlag.AlignTop)
        self.desc_edit = QTextEdit()
        self.desc_edit.setMinimumHeight(100)
        form_layout.addWidget(self.desc_edit, 3, 1, 1, 2)

        layout.addLayout(form_layout)

        # 图片选择区域
        images_layout = QHBoxLayout()
        images_layout.setAlignment(Qt.AlignmentFlag.AlignCenter)

        # 封面图片选择
        template_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'template')
        cover_template = os.path.join(
            template_dir, 'OEBPS', 'Images', 'cover.jpg')
        self.cover_selector = ImageSelector("封面图片", cover_template, self)
        images_layout.addWidget(self.cover_selector)

        # 背景图片选择
        back_template = os.path.join(
            template_dir, 'OEBPS', 'Images', 'bg1.jpg')
        self.back_selector = ImageSelector("背景图片", back_template, self)
        images_layout.addWidget(self.back_selector)

        layout.addLayout(images_layout)

        # 转换按钮
        self.convert_button = QPushButton("开始转换")
        self.convert_button.setMinimumHeight(40)
        self.convert_button.setFont(QFont("Arial", 12, QFont.Bold))
        self.convert_button.clicked.connect(self.start_conversion)
        layout.addWidget(self.convert_button)

    def setup_log_tab(self):
        layout = QVBoxLayout(self.log_tab)

        # 日志文本框
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setFont(QFont("Courier New", 10))
        layout.addWidget(self.log_text)

        # 清除日志按钮
        self.clear_log_button = QPushButton("清除日志")
        self.clear_log_button.clicked.connect(self.clear_log)
        layout.addWidget(self.clear_log_button)

    def browse_txt_file(self):
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择TXT文件", "", "文本文件 (*.txt)"
        )
        if file_path:
            self.txt_path_edit.setText(file_path)

            # 尝试从文件名提取书名和作者
            filename = os.path.basename(file_path)
            filename_without_ext = os.path.splitext(filename)[0]

            # 常见的分隔模式：书名-作者，书名_作者，书名（作者），书名[作者]等
            patterns = [
                r'(.+)[\-_](.+)',  # 匹配 书名-作者 或 书名_作者
                r'(.+)\((.+)\)',  # 匹配 书名(作者)
                r'(.+)\[(.+)\]',   # 匹配 书名[作者]
                r'《(.+)》作者：(.+)',  # 匹配 《书名》 作者：作者名
                r'(.+)\s+作者：(.+)',   # 匹配 书名 作者：作者名
                r'《(.+)》.*作者[：:]*(.+)',  # 匹配 《书名》和作者之间包含任意字符
                r'《(.+)》',  # 匹配 《书名》
                r'(.+)'  # 匹配 书名
            ]

            for pattern in patterns:
                match = re.match(pattern, filename_without_ext)
                if match:
                    if len(match.groups()) == 2:
                        book_name, author = match.groups()
                        self.book_name_edit.setText(book_name.strip())
                        self.author_edit.setText(author.strip())
                    else:
                        book_name = match.group(1)
                        self.book_name_edit.setText(book_name.strip())
                    break

    def clear_log(self):
        self.log_text.clear()

    def start_conversion(self):
        # 检查必填字段
        txt_path = self.txt_path_edit.text()
        if not txt_path or not os.path.exists(txt_path):
            QMessageBox.warning(self, "错误", "请选择有效的TXT文件")
            return

        book_name = self.book_name_edit.text()
        if not book_name:
            QMessageBox.warning(self, "错误", "请输入书名")
            return

        author_name = self.author_edit.text()
        if not author_name:
            QMessageBox.warning(self, "错误", "请输入作者名")
            return

        desc = self.desc_edit.toPlainText()
        if not desc:
            QMessageBox.warning(self, "错误", "请输入小说简介")
            return

        cover_image_path = self.cover_selector.selected_image_path
        back_image_path = self.back_selector.selected_image_path

        # 切换到日志标签
        self.tabs.setCurrentIndex(1)

        # 禁用转换按钮
        self.convert_button.setEnabled(False)
        self.convert_button.setText("转换中...")

        # 创建并启动转换线程
        self.conversion_thread = ConversionThread(
            txt_path, book_name, author_name, desc, cover_image_path, back_image_path
        )
        self.conversion_thread.finished.connect(self.conversion_finished)
        self.conversion_thread.start()

    def conversion_finished(self, success, error_message):
        # 恢复转换按钮
        self.convert_button.setEnabled(True)
        self.convert_button.setText("开始转换")

        if success:
            QMessageBox.information(self, "成功", "EPUB文件已成功创建！")
        else:
            if error_message:
                QMessageBox.critical(self, "错误", f"转换失败: {error_message}")
            else:
                QMessageBox.critical(self, "错误", "转换失败，请查看日志获取详细信息")

    def closeEvent(self, event):
        # 恢复标准输出
        sys.stdout = self.log_redirector.old_stdout
        sys.stderr = self.log_redirector.old_stderr
        event.accept()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    # 设置应用程序图标
    icon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'favicon.ico')
    if os.path.exists(icon_path):
        app.setWindowIcon(QIcon(icon_path))
        myappid = 'txt2epub.1.0'  # 任意字符串，作为应用程序ID
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
